import { _decorator, Node, director, color, System } from 'cc';
import { BaseManager } from '../libs/rxjs/cc3/BaseManager';
import { auditTime, bindCallback, map, NEVER, Observable, of, tap } from 'rxjs';
import { ReactiveProperty } from '../libs/rxjs/cc3/ReactiveProperty';
import { ReactiveCommand } from '../libs/rxjs/cc3/ReactiveCommand';
import { sceneScheduler } from '../libs/rxjs/cc3/schedule/creator';
const { ccclass, property } = _decorator;

@ccclass('PlayFabManager')
export class PlayFabManager extends BaseManager {

    public static instance: PlayFabManager;
    static ID = 'playfab_system';
    get logColorOverride() { return color().fromHEX('#e76832') };

    static registerSystem() {
        director.unregisterSystem(director.getSystem(PlayFabManager.ID));
        director.registerSystem(PlayFabManager.ID, pfm, System.Priority.MEDIUM);
        pfm.init();
    }

    titleId = '85017';

    enabled = ReactiveProperty.Create(true);

    saveUserDataCommand = ReactiveCommand.Create<string>();

    useObserves() {
        return [
            this.saveUserDataCommand._subject.pipe(auditTime(1000, sceneScheduler)).subscribe(_ => this.updateUserData(_)),
        ];
    }

    onInitManager(): void {
        PlayFab.settings.titleId = this.titleId;
    }

    fnv1aHash(str: string): number {
        let hash = 2166136261; // FNV 偏移基础值
        for (let i = 0; i < str.length; i++) {
            hash ^= str.charCodeAt(i);
            hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);
        }
        return hash >>> 0; // 确保无符号整数
    }

    generatePlayerNumber(playfabId?: string): string {
        playfabId = playfabId ?? this.playFabId.value;
        const hash = this.fnv1aHash(playfabId);
        const number = (hash % 90000) + 10000; // 5 位数
        return `Player${number}`;
    }

    playFabId = ReactiveProperty.Create<string>(null);
    displayName = ReactiveProperty.Create<string>(null);
    entityId = ReactiveProperty.Create<string>(null);
    userData = ReactiveProperty.Create<string>(null);
    // myRank = ReactiveProperty.Create<number>(null);
    myRanking = ReactiveProperty.Create<any>(null);

    // my

    loginWithCustomId(customId: string) {
        if (!this.enabled.value) return NEVER;
        let bcb = bindCallback(PlayFabClientSDK.LoginWithCustomID.bind(this));
        return bcb({
            CustomId: customId,
            CreateAccount: true,
            InfoRequestParameters: {
                GetPlayerProfile: true,
                GetUserData: true,
            }
        }).pipe(map((_: any) => {
            this.log('@loginWithCustomId', _);
            if (_?.[0]?.code == 200) {
                this.playFabId.value = _[0].data?.PlayFabId;
                this.entityId.value = _[0].data?.EntityToken?.Entity?.Id;
                this.displayName.value = _[0].data?.InfoResultPayload?.PlayerProfile?.DisplayName;
                this.userData.value = _[0].data?.InfoResultPayload?.UserData?.data?.Value;

                if (this.entityId.value != null) {
                    this.getLeaderboardForEntities('stageNum_manual', [this.entityId.value]).subscribe();
                }
            }
            return _;
        }));
    }

    getProfile() {
        if (!this.enabled.value) return NEVER;
        if (this.playFabId.value == null) return of(null);
        let bcb = bindCallback(PlayFabProfilesSDK.GetProfile.bind(this));
        return bcb({}).pipe(map((_: any) => {
            if (_?.[0]?.code == 200) {
                this.displayName.value = _[0].data?.Profile?.DisplayName;
            }
            return _;
        }));
    }

    setDisplayName(displayName: string) {
        if (!this.enabled.value) return NEVER;
        if (this.playFabId.value == null) return of(null);
        let bcb = bindCallback(PlayFabProfilesSDK.SetDisplayName.bind(this));
        return bcb({ DisplayName: displayName }).pipe(map((_: any) => {
            this.log('@setDisplayName', _);
            return _;
        }));
    }

    updateUserData(data: string) {
        if (!this.enabled.value) return NEVER;
        this.log('@save -updateUserData');
        return bindCallback(PlayFabClientSDK.UpdateUserData.bind(this))({ Data: { data } }).pipe(tap((_: any) => this.log('@UpdateUserData result', _)));
    }

    getUserData() {
        if (!this.enabled.value) return NEVER;
        return bindCallback(PlayFabClientSDK.GetUserData.bind(this))({}).pipe(tap(_ => this.log('@getUserData result', _)));
    }

    updateLeaderboardEntries(LeaderboardName: string, score: number) {
        if (!this.enabled.value) return NEVER;
        if (this.entityId.value == null) return of(null);
        let bcb = bindCallback(PlayFabProgressionSDK.UpdateLeaderboardEntries.bind(this));
        return bcb({
            Entries: [{
                EntityId: this.entityId.value,
                Scores: [score],
            }], LeaderboardName
        }).pipe(map((_: any) => {
            this.log('@UpdateLeaderboardEntries', _);
            if (_?.[0]?.code == 200) {
                this.getLeaderboardForEntities(LeaderboardName, [this.entityId.value]).subscribe();
            }
            return _;
        }));
    }

    getLeaderboardForEntities(LeaderboardName: string, entityIds: string[]) {
        if (!this.enabled.value) return NEVER;
        if (this.playFabId.value == null) return of(null);
        if (this.entityId.value == null) return of(null);
        let bcb = bindCallback(PlayFabProgressionSDK.GetLeaderboardForEntities.bind(this));
        return bcb({ LeaderboardName, EntityIds: entityIds }).pipe(map((_: any) => {
            this.log('@GetLeaderboardForEntities', _);
            for (let i = 0; i < _.length; i++) {
                let item = _[i];
                for (let j = 0; j < (item?.data?.Rankings?.length ?? 0); j++) {
                    let ranking = item.data.Rankings[j];
                    if (ranking.Entity.Id == this.entityId.value) {
                        this.myRanking.value = ranking;
                        break;
                    }
                }
            }
            return _;
        }));
    }

    getLeaderboard(LeaderboardName: string, StartingPosition: number, PageSize: number) {
        if (!this.enabled.value) return NEVER;
        if (this.playFabId.value == null) return of(null);
        let bcb = bindCallback(PlayFabProgressionSDK.GetLeaderboard.bind(this));
        return bcb({ LeaderboardName, PageSize: PageSize, StartingPosition }).pipe(map((_: any) => {
            this.log('@GetLeaderboard', _);
            return _;
        }));
    }

}

globalThis.PlayFabManager = PlayFabManager;

export const pfm = PlayFabManager.instance = new PlayFabManager();
